#odf modifier
#To use, you must provide the target odf
#only works with HCT

from .lib.StructReader import *
from .lib.StructWriter import *

class ODFModifier(object):
    
    def __init__(self, obj3D, inFile):
        
        self.obj3D = obj3D
        self.inFile = inFile
        self.outFile = None
        self.meshes = []
            
    def write_vertices(self, meshName, numVerts):
        
        for i in xrange(numVerts):
            coords = self.obj3D.get_coords(meshName, i)
            normals = self.obj3D.get_vert_normals(meshName, i)
            weights = self.obj3D.get_vert_weights(meshName, i, 4)
            uv = self.obj3D.get_vert_uv(meshName, i)
            bones = self.obj3D.get_vert_bones(meshName, i, 4)
            
            self.outFile.write_float(*coords)
            self.outFile.write_float(*weights)
            self.outFile.write_float(*normals)
            self.outFile.write_ubyte(*bones)
            self.outFile.write_float(*uv)
    
    def write_faces(self, meshName, numFaces):
        
        for i in xrange(numFaces):
            indices = self.obj3D.get_face_verts(meshName, i)
            self.outFile.write_ushort(*indices[:3])
        
    def parse_HCT_submesh(self):
        
        curPos = self.inFile.tell()
        meshName = self.inFile.read_string(64, '\x00')
        
        meshID, matNum, null, matID, texID = self.inFile.read_long(5)
        texInfo = self.inFile.read_long(9)
        numVerts = self.inFile.read_long()
        numIndex = self.inFile.read_long()
        matFlag = self.inFile.read_long(4)
        numFaces = numIndex / 3
        
        if meshName in self.meshes:
            newVerts = self.obj3D.vert_count(meshName)
            newFaces = self.obj3D.face_count(meshName)
            newIndex = newFaces * 3
            print meshName
            #print meshName
            #print "old: %d verts, %d faces" %(numVerts, numFaces)
            #print "new: %d verts, %d faces" %(newVerts, newFaces)
            
            self.inFile.seek(curPos)
            
            #write new name
            self.outFile.write_string(meshName, 64)
            self.inFile.seek(64, 1)
            self.outFile.write(self.inFile.read(20))
            self.outFile.write(self.inFile.read(36))
            self.outFile.write_ulong(newVerts, newIndex)
            self.inFile.seek(8, 1)
            self.outFile.write(self.inFile.read(16))
            self.write_vertices(meshName, newVerts)
            self.write_faces(meshName, newFaces)
            
            self.inFile.seek(numVerts * 52, 1)
            self.inFile.seek(numFaces * 6, 1)
            self.outFile.write(self.inFile.read(24))
            return 168 + (newVerts * 52) + (newIndex * 2)
        else:
            self.inFile.seek(curPos)
            self.outFile.write(self.inFile.read(144))
            self.outFile.write(self.inFile.read(numVerts * 52))
            self.outFile.write(self.inFile.read(numIndex * 2))
            self.outFile.write(self.inFile.read(24))
            return 168 + (numVerts * 52) + (numIndex * 2)
        
    def parse_mesh(self):
        
        sectLen = self.inFile.read_long()
        sectEnd = self.inFile.tell() + sectLen
        
        self.meshes = set(self.obj3D.get_objects())         
        self.outFile.write_string("MESH")        
        chunkPos = self.outFile.tell()
        self.outFile.write_ulong(sectLen)
        newChunkSize = 0
        
        while self.inFile.tell() != sectEnd:
            
            curPos = self.inFile.tell()
            name = self.inFile.read_string(64, '\x00')
            meshID, numSubMesh = self.inFile.read_long(2)
            
            self.inFile.seek(curPos)
            self.outFile.write(self.inFile.read(72))
            newChunkSize += 72
            for i in xrange(numSubMesh):
                newChunkSize += self.parse_HCT_submesh()   
        curPos = self.outFile.tell()
        self.outFile.seek(chunkPos)
        self.outFile.write_ulong(newChunkSize)
        self.outFile.seek(curPos)
        
    def write_file(self):
        
        fsize = self.inFile.filesize()
        self.outFile = StructWriter(open("out.odf", 'wb'))
        
        self.outFile.write(self.inFile.read(12))
        
        while self.inFile.tell() != fsize:
            tag = self.inFile.read_string(4)
            if tag == "MESH":
                self.parse_mesh()
            else:                
                sectLen = self.inFile.read_long() 
                if tag == "BANM":
                    sectLen += 264
                self.inFile.seek(-8, 1)
                sectLen += 8
                self.outFile.write(self.inFile.read(sectLen))
        print "Wrote out out.odf"
        self.outFile.close()

def run(path, obj3D, target=""):
    
    openFile = StructReader(open(path, 'rb'))
    odf = ODFModifier(obj3D, openFile)
    odf.write_file()
    openFile.close()